using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Win32;
using Core;

namespace Services
{
	internal class RegistryService : IRegistryService
	{
		public IEnumerable<string> GetSubKeyNames(RegistryLocation location, string subKeyName)
		{
			using (RegistryKey registryKey = RegistryKey.OpenBaseKey(ConvertToRegistryHive(location), RegistryView.Registry32))
			{
				using (RegistryKey registryKey2 = registryKey.CreateSubKey(subKeyName))
				{
					if (registryKey2 == null)
					{
						throw new InvalidOperationException($"Registry key name '{subKeyName}' does not exist");
					}
					return registryKey2.GetSubKeyNames();
				}
			}
		}

		public bool DoesRegistryKeyNameExist(RegistryLocation location, string subKeyName, string name)
		{
			using (RegistryKey registryKey = RegistryKey.OpenBaseKey(ConvertToRegistryHive(location), RegistryView.Registry32))
			{
				using (RegistryKey registryKey2 = registryKey.OpenSubKey(subKeyName))
				{
					return registryKey2?.GetValue(name) != null;
				}
			}
		}

		public T GetValue<T>(RegistryLocation location, string subKeyName, string name)
		{
			using (RegistryKey registryKey = RegistryKey.OpenBaseKey(ConvertToRegistryHive(location), RegistryView.Registry32))
			{
				using (RegistryKey registryKey2 = registryKey.OpenSubKey(subKeyName))
				{
					object obj = registryKey2?.GetValue(name);
					if (obj == null)
					{
						throw new InvalidOperationException($"Registry key name '{name}' does not exist");
					}
					return (T)obj;
				}
			}
		}

		public void SetValue(RegistryLocation location, string subKeyName, string name, object value, RegistryValueType type)
		{
			using (RegistryKey registryKey = RegistryKey.OpenBaseKey(ConvertToRegistryHive(location), RegistryView.Registry32))
			{
				using (RegistryKey registryKey2 = registryKey.CreateSubKey(subKeyName))
				{
					registryKey2?.SetValue(name, value, ConvertToRegistryValueKind(type));
				}
			}
		}

		public void DeleteValue(RegistryLocation location, string subKeyName, string name)
		{
			using (RegistryKey registryKey = RegistryKey.OpenBaseKey(ConvertToRegistryHive(location), RegistryView.Registry32))
			{
				using (RegistryKey registryKey2 = registryKey.OpenSubKey(subKeyName, true))
				{
					if (registryKey2 != null && registryKey2.GetValueNames().Contains(name))
					{
						registryKey2.DeleteValue(name);
					}
				}
			}
		}

		public T TryGetValue<T>(RegistryLocation location, string path, string name, T defaultValue)
		{
			T result = defaultValue;
			try
			{
				if (DoesRegistryKeyNameExist(location, path, name))
				{
					result = GetValue<T>(location, path, name);
				}
			}
			catch (Exception)
			{
			}
			return result;
		}

		public void TrySetValue<T>(RegistryLocation location, string path, string name, T value)
		{
			try
			{
				SetValue(location, path, name, value, RegistryValueType.DWord);
			}
			catch (Exception)
			{
			}
		}

		private static RegistryHive ConvertToRegistryHive(RegistryLocation location)
		{
			switch (location)
			{
			case RegistryLocation.LocalMachine:
				return RegistryHive.LocalMachine;
			case RegistryLocation.CurrentUser:
				return RegistryHive.CurrentUser;
			default:
				throw new InvalidOperationException($"Registry hive not found for {location}");
			}
		}

		private static RegistryValueKind ConvertToRegistryValueKind(RegistryValueType type)
		{
			switch (type)
			{
			case RegistryValueType.String:
				return RegistryValueKind.String;
			case RegistryValueType.DWord:
				return RegistryValueKind.DWord;
			default:
				throw new InvalidOperationException($"Registry kind not found for {type}");
			}
		}
	}
}
